/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package es.miguelgonzalez.jgraficacomida;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.io.Serializable;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;



/**
 * Componente para editar la alimentación de una población a través de
 * unos textbox o de una gráfica.
 * @author Miguel González - Ceura
 */
public final class JGraficaComida extends JPanel implements 
        GraficaComidaChangeEventListener, Serializable {

    public static final int IDIOMA_E = 1;
    public static final int IDIOMA_I = 2;
    
    //Modelo de datos de la poblacion
    private JGraficaComidaModel modeloPoblacion;
    
    //Objetos gráficos para pintar el componente
    private JTextField txtAlimentoInicial;
    private JTextField txtDiaMaximo;
    private JTextField txtAlimentoMaximo;
    private JTextField txtAlimentoFinal;
    private JLabel lblAlimentoInicial;
    private JLabel lblDiaAlimentoMaximo;
    private JLabel lblAlimentoMaximo;
    private JLabel lblAlimentoFinal;
    private JGraficaComidaDibujo grafica;
    
    /**
     * Constructor por defecto del componente. Inicializa la población a
     * valores por defecto: alimentoInicial = 150, diaMax = 15,
     * alimentoMax = 150, alimentoFinal = 150
     */
    public JGraficaComida() {
        //Por defecto el modelo de la población es nulo
        modeloPoblacion = null;
        
        //Inicializamos el componente
        initPoblacion();
    }
    
    /**
     * Constructor del componente
     * @param modeloPoblacion Recibe un modelo de la población
     */
    public JGraficaComida(JGraficaComidaModel modeloPoblacion) {
        //Establecemos el modelo recibido como parámetro como nuestro modelo
        this.modeloPoblacion = modeloPoblacion;
        
        //Inicializamos el componente
        initPoblacion();
    }
    
    /**
     * Establece el idioma del componente
     * @param tipoIdioma IDIOMA_E o IDIOMA_I
     */
    public void cambiarIdioma(int tipoIdioma) {
        if(tipoIdioma == IDIOMA_E) {
            lblAlimentoInicial.setText("Alimento inicial: ");
            lblDiaAlimentoMaximo.setText("Día de alimento máximo: ");
            lblAlimentoMaximo.setText("Alimento máximo: ");
            lblAlimentoFinal.setText("Alimento final: ");
        } else if(tipoIdioma == IDIOMA_I) {
            lblAlimentoInicial.setText("Initial food: ");
            lblDiaAlimentoMaximo.setText("Day of maximum feeding: ");
            lblAlimentoMaximo.setText("Maximun feeding: ");
            lblAlimentoFinal.setText("Final feeding: ");
        }
    }
    
    /**
     * Devuelve el modelo de la población del componente
     * @return Modelo de la población
     */
    public JGraficaComidaModel getModeloPoblacion() {
        return modeloPoblacion;
    }
    
    /**
     * Establece un nuevo modelo de la población en el componente
     * @param modeloPoblacion Nuevo modelo de la población
     */
    public void setModeloPoblacion(JGraficaComidaModel modeloPoblacion) {
        this.modeloPoblacion = modeloPoblacion;
        
        //Nos quitamos de la escucha del antiguo modelo
        modeloPoblacion.removeChangeEventListener(this);
        
        //Nos añadimos a la escucha del  nuevo modelo
        modeloPoblacion.addChangeEventListener(this);
        
        grafica.setModelExperimento(modeloPoblacion);
    }

    /**
     * Inicializa el componente
     */
    private void initPoblacion() {
        if(modeloPoblacion == null) {
            //Si no recibe un modelo de la población lo creamos
            modeloPoblacion = new JGraficaComidaModel();
        }
        
        //Nos añadimos a la escucha del modelo de datos
        modeloPoblacion.addChangeEventListener(this);
        
        //Inicializamos los componentes Swing
        grafica = new JGraficaComidaDibujo(modeloPoblacion);
        
        lblAlimentoInicial = new JLabel("Alimento inicial: ", JLabel.TRAILING);
        txtAlimentoInicial = new JTextField(3);
        lblAlimentoInicial.setLabelFor(txtAlimentoInicial);
        
        lblDiaAlimentoMaximo = new JLabel("Día de alimento máximo: ",
                JLabel.TRAILING);
        txtDiaMaximo = new JTextField(5);
        lblDiaAlimentoMaximo.setLabelFor(txtDiaMaximo);
        
        lblAlimentoMaximo = new JLabel("Alimento máximo: ", JLabel.TRAILING);
        txtAlimentoMaximo = new JTextField(5);
        lblAlimentoMaximo.setLabelFor(txtAlimentoMaximo);
        
        lblAlimentoFinal = new JLabel("Alimento final: ", JLabel.TRAILING);
        txtAlimentoFinal = new JTextField(5);
        lblAlimentoFinal.setLabelFor(txtAlimentoFinal);
        
        //Inicializamos el panel
        setLayout(new BorderLayout());
        JPanel panelIzq = new JPanel();
        panelIzq.setLayout(new GridBagLayout());
        GridBagConstraints c = new GridBagConstraints();
        c.fill = GridBagConstraints.HORIZONTAL;
        c.ipadx = 10;

        c.gridx = 0;
        c.gridy = 0;
        panelIzq.add(lblAlimentoInicial, c);
        c.gridx = 1;
        c.gridy = 0;
        panelIzq.add(txtAlimentoInicial, c);
        c.gridx = 0;
        c.gridy = 1;
        panelIzq.add(lblDiaAlimentoMaximo, c);
        c.gridx = 1;
        c.gridy = 1;
        panelIzq.add(txtDiaMaximo, c);
        c.gridx = 0;
        c.gridy = 2;
        panelIzq.add(lblAlimentoMaximo, c);
        c.gridx = 1;
        c.gridy = 2;
        panelIzq.add(txtAlimentoMaximo, c);
        c.gridx = 0;
        c.gridy = 3;
        panelIzq.add(lblAlimentoFinal, c);
        c.gridx = 1;
        c.gridy = 3;
        panelIzq.add(txtAlimentoFinal, c);
        
        //Inicializamos los textos
        txtAlimentoInicial.setText(Integer.toString(
                modeloPoblacion.getAlimentoInicial()));
        txtDiaMaximo.setText(Integer.toString(
                modeloPoblacion.getDiaMax()));
        txtAlimentoMaximo.setText(Integer.toString(
                modeloPoblacion.getAlimentoMax()));
        txtAlimentoFinal.setText(Integer.toString(
                modeloPoblacion.getAlimentoFinal()));

        //Añadimos los paneles
        add(panelIzq, BorderLayout.WEST);
        JPanel panelGrafica = new JPanel();
        panelGrafica.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
        panelGrafica.setLayout(new BorderLayout());
        panelGrafica.add(grafica, BorderLayout.CENTER);
        add(panelGrafica, BorderLayout.CENTER);
        
        initListeners();
    }
    
    /**
     * Inicializa los listeners
     */
    private void initListeners() {
        txtAlimentoInicial.addFocusListener(new FocusListener() {
            @Override
            public void focusGained(FocusEvent e) {
            }

            @Override
            public void focusLost(FocusEvent e) {
                actualizarAlimentoInicial();
            }
            
        });
        txtAlimentoInicial.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                actualizarAlimentoInicial();
            }
        });
        
        txtDiaMaximo.addFocusListener(new FocusListener() {

            @Override
            public void focusGained(FocusEvent e) {
            }

            @Override
            public void focusLost(FocusEvent e) {
                actualizarDiaMaximo();
            }
            
        });
        txtDiaMaximo.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                actualizarDiaMaximo();
            }
        });
        
        txtAlimentoMaximo.addFocusListener(new FocusListener() {
            @Override
            public void focusGained(FocusEvent e) {}
            @Override
            public void focusLost(FocusEvent e) {
                actualizarAlimentoMaximo();
            }
        });
        
        txtAlimentoMaximo.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                actualizarAlimentoMaximo();
            }
        });
        
        txtAlimentoFinal.addFocusListener(new FocusListener() {
            @Override
            public void focusGained(FocusEvent e) {}
            @Override
            public void focusLost(FocusEvent e) {
                actualizarAlimentoFinal();
            }
        });
        txtAlimentoFinal.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                actualizarAlimentoFinal();
            }
        });
    }
    
    /**
     * Actualiza la alimentación inicial en el modelo
     */
    private void actualizarAlimentoInicial() {
        //Se resetea el color de fondo por si había un error
        lblAlimentoInicial.setForeground(Color.BLACK);
        //Si al perder el foco se detecta que se ha cambiado el alimento
        if(Integer.parseInt(txtAlimentoInicial.getText())
                != modeloPoblacion.getAlimentoInicial()) {
            try {
                modeloPoblacion.setAlimentoInicial(Integer.parseInt(
                        txtAlimentoInicial.getText()));
            } catch (GraficaComidaIncorrectValueException ex) {
                //Se pone en rojo el textbox
                lblAlimentoInicial.setForeground(Color.RED);
            }
        }
    }
    
    /**
     * Actualiza el día máximo en el modelo
     */
    private void actualizarDiaMaximo() {
        //Se resetea el color de fondo por si había un error
        lblDiaAlimentoMaximo.setForeground(Color.BLACK);
        //Si al perder el foco se detecta que se ha cambiado el alimento
        if(Integer.parseInt(txtDiaMaximo.getText())
                != modeloPoblacion.getDiaMax()) {
            try {
                modeloPoblacion.setDiaMax(Integer.parseInt(
                        txtDiaMaximo.getText()));       
            } catch (GraficaComidaIncorrectValueException ex) {
                //Se pone en rojo el textbox
                lblDiaAlimentoMaximo.setForeground(Color.RED);
            }
        }
    }
    
    /**
     * Actualiza el alimento máximo en el modelo
     */
    private void actualizarAlimentoMaximo() {
        //Se resetea el color de fondo por si había un error
        lblAlimentoMaximo.setForeground(Color.BLACK);
        //Si al perder el foco se detecta que se ha cambiado el alimento
        if(Integer.parseInt(txtAlimentoMaximo.getText())
                != modeloPoblacion.getAlimentoMax()) {
            try {
                modeloPoblacion.setAlimentoMax(Integer.parseInt(
                        txtAlimentoMaximo.getText()));
            } catch (GraficaComidaIncorrectValueException ex) {
                //Se pone en rojo el textbox
                lblAlimentoMaximo.setForeground(Color.RED);
            }
        }
    }
    
    /**
     * Actualiza el alimento final en el modelo
     */
    private void actualizarAlimentoFinal() {
        //Se resetea el color de fondo por si había un error
        lblAlimentoFinal.setForeground(Color.BLACK);
        //Si al perder el foco se detecta que se ha cambiado el alimento
        if(Integer.parseInt(txtAlimentoFinal.getText())
                != modeloPoblacion.getAlimentoFinal()) {
            try {
                modeloPoblacion.setAlimentoFinal(Integer.parseInt(
                        txtAlimentoFinal.getText()));
            } catch (GraficaComidaIncorrectValueException ex) {
                //Se pone en rojo el textbox
                lblAlimentoFinal.setForeground(Color.RED);
            }
        }
    }

    /**
     * Método que dispara los cambios en el modelo a todos los listeners
     * que se han suscrito a la escucha de los cambios
     * @param ev Cambio producido
     */
    @Override
    public void fireChangeEvent(GraficaComidaChangeEvent ev) {
        //Actualizamos los JTextFields según la propiedad que ha cambiado
        if(ev.getPropertyName().equals(GraficaComidaChangeEvent.ALIMENTO_INICIAL)) {
            lblAlimentoInicial.setForeground(Color.BLACK);
            txtAlimentoInicial.setText(Integer.toString(ev.getNewValue()));
        } else if(ev.getPropertyName().equals(GraficaComidaChangeEvent.DIA_MAX)) {
            lblDiaAlimentoMaximo.setForeground(Color.BLACK);
            txtDiaMaximo.setText(Integer.toString(ev.getNewValue()));
        } else if(ev.getPropertyName().equals(GraficaComidaChangeEvent.ALIMENTO_MAX)) {
            lblAlimentoMaximo.setForeground(Color.BLACK);
            txtAlimentoMaximo.setText(Integer.toString(ev.getNewValue()));
        } else if(ev.getPropertyName().equals(GraficaComidaChangeEvent.ALIMENTO_FINAL)) {
            lblAlimentoFinal.setForeground(Color.BLACK);
            txtAlimentoFinal.setText(Integer.toString(ev.getNewValue()));
        }
    }
}